using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Net.Http;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.Owin;
using Microsoft.Owin.Infrastructure;
using Microsoft.Owin.Logging;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Infrastructure;
using Newtonsoft.Json.Linq;
using Sharp.Platform.Owin.OAuth.WeiBo.Provider;

namespace Sharp.Platform.Owin.OAuth.WeiBo
{
    public class AuthenticationHandler : AuthenticationHandler<WeiBoAuthenticationOptions>
    {
        private readonly string _authorizeUrl = "https://api.weibo.com/oauth2/authorize";

        private readonly string _access_tokenUrl = "https://api.weibo.com/oauth2/access_token";

        private readonly string _showUserUrl = "https://api.weibo.com/2/users/show.json";

        private readonly ILogger _logger;

        private readonly HttpClient _httpClient;

        public AuthenticationHandler(HttpClient httpClient, ILogger logger)
        {
            _httpClient = httpClient;
            _logger = logger;
        }

        protected override async Task<AuthenticationTicket> AuthenticateCoreAsync()
        {
            string text = null;
            string text2 = null;
            IReadableStringCollection query = base.Request.Query;
            IList<string> values = query.GetValues("code");
            if (values != null && values.Count == 1)
            {
                text = values[0];
            }
            values = query.GetValues("state");
            if (values != null && values.Count == 1)
            {
                text2 = values[0];
            }
            var authenticationProperties = Options.StateDataFormat.Unprotect(text2);
            AuthenticationTicket result;
            if (authenticationProperties == null)
            {
                result = null;
            }
            else
            {
                List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>
                {
                    new KeyValuePair<string, string>("client_id", base.Options.AppKey),
                    new KeyValuePair<string, string>("client_secret", base.Options.AppSecret),
                    new KeyValuePair<string, string>("redirect_uri", this.GenerateRedirectUri()),
                    new KeyValuePair<string, string>("code", text),
                    new KeyValuePair<string, string>("grant_type", "authorization_code")
                };
                NameValueCollection nameValueCollection =
                    new NameValueCollection
                    {
                        {"client_id", base.Options.AppKey},
                        {"client_secret", base.Options.AppSecret},
                        {"redirect_uri", this.GenerateRedirectUri()},
                        {"code", text},
                        {"grant_type", "authorization_code"}
                    };
                string format = this._access_tokenUrl + "?client_id={0}&client_secret={1}&grant_type=authorization_code&redirect_uri={3}&code={2}";
                string requestUri = string.Format(format, new object[]
                {
                    Uri.EscapeDataString(base.Options.AppKey),
                    Uri.EscapeDataString(base.Options.AppSecret),
                    Uri.EscapeDataString(text),
                    Uri.EscapeDataString(this.GenerateRedirectUri())
                });
                HttpResponseMessage httpResponseMessage = await this._httpClient.PostAsync(requestUri, new StringContent(""), base.Request.CallCancelled);
                httpResponseMessage.EnsureSuccessStatusCode();
                string text3 = await httpResponseMessage.Content.ReadAsStringAsync();
                JObject jObject = JObject.Parse(text3);
                string text4 = jObject["access_token"].ToString();
                string stringToEscape = jObject["uid"].ToString();
                string refreshToken = jObject.Value<string>("refresh_token");
                string expires = jObject.Value<string>("expires_in");
                if (string.IsNullOrWhiteSpace(text4))
                {
                    LoggerExtensions.WriteWarning(this._logger, "Access token was not found", new string[0]);
                    result = new AuthenticationTicket(null, authenticationProperties);
                }
                else
                {
                    HttpResponseMessage httpResponseMessage2 = await this._httpClient.GetAsync(string.Concat(new string[]
                    {
                        this._showUserUrl,
                        "?access_token=",
                        Uri.EscapeDataString(text4),
                        "&uid=",
                        Uri.EscapeDataString(stringToEscape)
                    }), base.Request.CallCancelled);
                    httpResponseMessage2.EnsureSuccessStatusCode();
                    string text5 = await httpResponseMessage2.Content.ReadAsStringAsync();
                    JObject user = JObject.Parse(text5);
                    WeiBoAuthenticatedContext weiBoAuthenticatedContext = new WeiBoAuthenticatedContext(base.Context, user, text4, refreshToken, expires);
                    weiBoAuthenticatedContext.Identity = new ClaimsIdentity(new Claim[]
                    {
                        new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", weiBoAuthenticatedContext.Id, "http://www.w3.org/2001/XMLSchema#string", base.Options.AuthenticationType),
                        new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", weiBoAuthenticatedContext.Name, "http://www.w3.org/2001/XMLSchema#string", base.Options.AuthenticationType),
                        new Claim("urn:weibotaccount:id", weiBoAuthenticatedContext.Id, "http://www.w3.org/2001/XMLSchema#string", base.Options.AuthenticationType),
                        new Claim("urn:weiboaccount:name", weiBoAuthenticatedContext.Name, "http://www.w3.org/2001/XMLSchema#string", base.Options.AuthenticationType)
                    }, base.Options.AuthenticationType, "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", "http://schemas.microsoft.com/ws/2008/06/identity/claims/role");
                    await base.Options.Provider.Authenticated(weiBoAuthenticatedContext);
                    weiBoAuthenticatedContext.Properties = authenticationProperties;
                    result = new AuthenticationTicket(weiBoAuthenticatedContext.Identity, weiBoAuthenticatedContext.Properties);
                }
            }
            return result;
        }

        private string GenerateRedirectUri()
        {
            string arg = base.Request.Scheme + "://" + base.Request.Host;
            return arg + base.RequestPathBase + base.Options.CallbackPath;
        }

        protected override Task ApplyResponseChallengeAsync()
        {
            if (base.Response.StatusCode == 401)
            {
                AuthenticationResponseChallenge authenticationResponseChallenge = base.Helper.LookupChallenge(base.Options.AuthenticationType, base.Options.AuthenticationMode);
                if (authenticationResponseChallenge != null)
                {
                    AuthenticationProperties properties = authenticationResponseChallenge.Properties;
                    if (string.IsNullOrEmpty(properties.RedirectUri))
                    {
                        properties.RedirectUri = base.Request.Uri.ToString();
                    }
                    string stringToEscape = base.Options.StateDataFormat.Protect(properties);
                    string text = string.Concat(new string[]
                    {
                        this._authorizeUrl,
                        "?client_id=",
                        Uri.EscapeDataString(base.Options.AppKey),
                        "&scope=",
                        Uri.EscapeDataString("email"),
                        "&response_type=code&redirect_uri=",
                        Uri.EscapeDataString(this.GenerateRedirectUri()),
                        "&state=",
                        Uri.EscapeDataString(stringToEscape)
                    });
                    base.Response.Redirect(text);
                }
            }
            return Task.FromResult<object>(null);
        }

        public override async Task<bool> InvokeAsync()
        {
            bool result;
            if (base.Options.CallbackPath.HasValue && base.Options.CallbackPath == base.Request.Path)
            {
                AuthenticationTicket authenticationTicket = await base.AuthenticateAsync();
                if (authenticationTicket == null)
                {
                    LoggerExtensions.WriteWarning(this._logger, "Invalid return state, unable to redirect.", new string[0]);
                    base.Response.StatusCode = (500);
                    result = true;
                }
                else
                {
                    WeiBoReturnEndpointContext weiBoReturnEndpointContext = new WeiBoReturnEndpointContext(base.Context, authenticationTicket);
                    weiBoReturnEndpointContext.SignInAsAuthenticationType = base.Options.SignInAsAuthenticationType;
                    weiBoReturnEndpointContext.RedirectUri = authenticationTicket.Properties.RedirectUri;
                    authenticationTicket.Properties.RedirectUri = null;
                    await base.Options.Provider.ReturnEndpoint(weiBoReturnEndpointContext);
                    if (weiBoReturnEndpointContext.SignInAsAuthenticationType != null && weiBoReturnEndpointContext.Identity != null)
                    {
                        ClaimsIdentity claimsIdentity = weiBoReturnEndpointContext.Identity;
                        if (!string.Equals(claimsIdentity.AuthenticationType, weiBoReturnEndpointContext.SignInAsAuthenticationType, StringComparison.Ordinal))
                        {
                            claimsIdentity = new ClaimsIdentity(claimsIdentity.Claims, weiBoReturnEndpointContext.SignInAsAuthenticationType, claimsIdentity.NameClaimType, claimsIdentity.RoleClaimType);
                        }
                        base.Context.Authentication.SignIn(weiBoReturnEndpointContext.Properties, claimsIdentity);
                    }
                    if (!weiBoReturnEndpointContext.IsRequestCompleted && weiBoReturnEndpointContext.RedirectUri != null)
                    {
                        if (weiBoReturnEndpointContext.Identity == null)
                        {
                            weiBoReturnEndpointContext.RedirectUri = WebUtilities.AddQueryString(weiBoReturnEndpointContext.RedirectUri, "error", "access_denied");
                        }
                        Response.Redirect(weiBoReturnEndpointContext.RedirectUri);
                        weiBoReturnEndpointContext.RequestCompleted();
                    }
                    result = weiBoReturnEndpointContext.IsRequestCompleted;
                }
            }
            else
            {
                result = false;
            }
            return result;
        }
    }
}
